/// 使用vtkEdgePoints获取轮廓点并显示
///
#include <vtkActor.h>
#include <vtkContourFilter.h>
#include <vtkDoubleArray.h>
#include <vtkNamedColors.h>
#include <vtkPointData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
#include <vtkStructuredPoints.h>
#include <vtkEdgePoints.h>
#include <vtkOutlineFilter.h>
#include <vtkGenericCell.h>
#include <vtkMergePoints.h>

int main(int, char*[])
{
    auto vol =
            vtkSmartPointer<vtkStructuredPoints>::New();
    int dim = 11; // 26
    vol->SetDimensions(dim, dim, dim);
    vol->SetOrigin(-0.5, -0.5, -0.5);
    auto sp = 1.0 / (dim-1);
    vol->SetSpacing(sp, sp, sp);

    auto scalars =
            vtkSmartPointer<vtkDoubleArray>::New();
    scalars->SetNumberOfComponents(1);
    scalars->SetNumberOfTuples(dim * dim * dim);
    for (auto k = 0; k < dim; k++)
    {
        auto z = -0.5 + k * sp;
        auto kOffset = k * dim * dim;
        for (auto j = 0; j < dim; j++)
        {
            auto y = -0.5 + j * sp;
            auto jOffset = j * dim;
            for (auto i = 0; i < dim; i++)
            {
                auto x = -0.5 + i * sp;
                auto s = x * x + y * y + z * z - (0.4 * 0.4);
                auto offset = i + jOffset + kOffset;
                scalars->InsertTuple(offset, &s);
            }
        }
    }
    vol->GetPointData()->SetScalars(scalars);


    vtkSmartPointer<vtkEdgePoints> isoExtractor =
      vtkSmartPointer<vtkEdgePoints>::New();
    isoExtractor->SetInputData(vol);
    isoExtractor->SetValue(0);
    //isoExtractor->SetDebug(true);
    isoExtractor->Update();

    if(0){
        vtkStructuredPoints* data = vol.GetPointer();
        //data->Print(std::cout);
        vtkIdType numCells = data->GetNumberOfCells();
        cout << "numCells: " << numCells << endl;

//        vtkIdType estimatedSize = 1024;
//        vtkPoints* newPts = vtkPoints::New();
//        newPts->Allocate(estimatedSize, estimatedSize / 2);

//        vtkMergePoints* Locator = vtkMergePoints::New();
//        Locator->InitPointInsertion(newPts, data->GetBounds());

        vtkDataArray *inScalars = data->GetPointData()->GetScalars();
        vtkDataArray* cellScalars=inScalars->NewInstance();
        cellScalars->SetNumberOfComponents(inScalars->GetNumberOfComponents());
        cellScalars->Allocate(VTK_CELL_SIZE * inScalars->GetNumberOfComponents());

        vtkIdType cellId;
        //vtkGenericCell *cell = vtkGenericCell::New();

        for (cellId = 0; cellId < numCells ; cellId+=numCells/50) {
            vtkCell *cell = data->GetCell(cellId);
            cout << "cellId:" << cellId << endl;

            cell->Print(cout);
            vtkIdType numPtInCell = cell->GetNumberOfPoints();
            cout << "  numPtInCell:" << numPtInCell << endl;
            //vtkIdList* pids = cell->GetPointIds();

            //inScalars->GetTuples(cell->PointIds, cellScalars);
            //cellScalars->Print(cout);

            vtkIdType numEdges = cell->GetNumberOfEdges();

            cout << "numEdges:" << numEdges << endl;
            for (vtkIdType edgeId = 0; edgeId < numEdges; edgeId++)
            {
                vtkCell *edge = cell->GetEdge(edgeId);
                cout <<edgeId << ": " << edge->GetPointId(0) << "," << edge->GetPointId(1) << endl;
                // edge->Print(cout);
            }
            cout << endl;
            break;

        }

        cellScalars->Delete();
        //cell->Delete();
        //Locator->Delete();
    }

    // 读取轮廓数据
    if (1) {
        vtkPolyData *isoData = isoExtractor->GetOutput();
        vtkIdType numPoints = isoData->GetNumberOfPoints();
        vtkIdType numCells = isoData->GetNumberOfCells();
        cout << "numPoints: " << numPoints << endl;
        cout << "numCells: " << numCells << endl;

        double* bounds = isoData->GetBounds();
        cout << "bounds: " << bounds[0] <<", " << bounds[1] << ", " <<bounds[2] << ", "
             << bounds[3] <<", " << bounds[4] << ", " <<bounds[5] <<endl;
        cout << "get all points: " << endl;
        double range[2];
        isoData->GetScalarRange(range);
        cout << "Range: " << range[0] << ", " << range[1] << endl;

        // 读取每一个坐标点和对应存放的值
        for (vtkIdType ptId = 0; ptId < numPoints; ptId++) {
            double *v = isoData->GetPointData()->GetScalars()->GetTuple(ptId);
            double *x = isoData->GetPoint(ptId);
            cout << x[0] <<", " << x[1] << ", " << x[2] << " v:" << v[0] <<endl;
        }
    }
    auto colors =
            vtkSmartPointer<vtkNamedColors>::New();
    std::array<unsigned char , 4> isoColor{{255, 125, 125}};
      colors->SetColor("IsoColor", isoColor.data());
    std::array<unsigned char , 4> bkg{{51, 77, 102, 255}};
      colors->SetColor("BkgColor", bkg.data());

    auto renderer =
            vtkSmartPointer<vtkRenderer>::New();
    auto renWin =
            vtkSmartPointer<vtkRenderWindow>::New();
    renWin->AddRenderer(renderer);
    auto iren =
            vtkSmartPointer<vtkRenderWindowInteractor>::New();
    iren->SetRenderWindow(renWin);

    vtkSmartPointer<vtkPolyDataMapper> isoMapper =
            vtkSmartPointer<vtkPolyDataMapper>::New();
    isoMapper->SetInputConnection(isoExtractor->GetOutputPort());
    isoMapper->ScalarVisibilityOff();

    vtkSmartPointer<vtkActor> iso =
      vtkSmartPointer<vtkActor>::New();
    iso->SetMapper(isoMapper);
    iso->GetProperty()->EdgeVisibilityOn();
    iso->GetProperty()->SetDiffuseColor(colors->GetColor3d("IsoColor").GetData());

    // An outline provides context around the data.
    //
//    vtkSmartPointer<vtkOutlineFilter> outlineData =
//      vtkSmartPointer<vtkOutlineFilter>::New();
//    outlineData->SetInputData(vol);

//    vtkSmartPointer<vtkPolyDataMapper> mapOutline =
//      vtkSmartPointer<vtkPolyDataMapper>::New();
//    mapOutline->SetInputConnection(outlineData->GetOutputPort());

//    vtkSmartPointer<vtkActor> outline =
//      vtkSmartPointer<vtkActor>::New();
//    outline->SetMapper(mapOutline);
//    outline->GetProperty()->SetColor(colors->GetColor3d("Black").GetData());

    //renderer->AddActor(outline);
    renderer->AddActor(iso);
    renderer->SetBackground(colors->GetColor3d("BkgColor").GetData());
    renWin->SetSize(640, 480);

    // interact with data
    renWin->Render();
    iren->Initialize();
    iren->Start();

    return EXIT_SUCCESS;
}
